iT邦幫忙

2023 iThome 鐵人賽

DAY 9
0

當專案規模越來越大,會需要許多子目錄以便管理程式碼,通常每一個子目錄都要有自己的CMakeLists.txt負責處理該目錄的檔案,因此本篇會介紹如建立與管理子目錄。

語法

add_subdirectory

定義:將子目錄加入編譯

add_subdirectory(source_dir [binary_dir])
source_dir : 子目錄路徑(相對於目前這個CMakeLists.txt)
binary_dir : binary輸出路徑(會影響CMAKE_CURRENT_BINARY_DIR變數)

$ {CMAKE_CURRENT_BINARY_DIR}

定義:編譯出的二進制檔案所在位置
在add_subdirectory(filename [ ])的 binary_dir 沒有指定的情況下為$(PROJECT_BINARY_DIR)/filename

$ {CMAKE_CURRENT_SOURCE_DIR}

定義:現在的 CMakeListx.txt 檔案原始碼所在位置。

add_library

定義:將原始碼編譯成不同格式的二進制檔,之後會詳細介紹,今天會將原始碼編譯成Object檔(.o file)。

add_library(<name> OBJECT <source>)
name : 二進制檔名稱
source : 原始碼檔名

target_include_directories

定義:指定二進制檔案要包含的include目錄

target_include_directories(<target> <INTERFACE|PUBLIC|PRIVATE> [items])
target : 二進制檔案要名稱
<INTERFACE|PUBLIC|PRIVATE> : 選擇將include路徑是否向上傳遞,這個概念未來會講解。
items : include 的標頭檔路徑

target_link_libraries

定義:將執行檔與二進制檔鍊結起來

target_link_libraries(<target> ... <item>...)
target : 執行檔名稱
item : 要與執行檔鍊結的二進制檔案名稱

範例

$ git clone https://github.com/m11112089/2023_iT_CMake.git
$ cd ~/2023_iT_CMake/Day9/1

第一種情況

目錄結構為

├── build
├── CMakeLists.txt
├── MathFunctions
│   ├── CMakeLists.txt
│   ├── include
│   │   └── mysqrt.h
│   └── src
│       └── mysqrt.cpp
└── src
    └── main.cpp

Day9 / CMakeLists.txt

頂層 CMakeLists.txt 需要將MathFunctions加入下層目錄中,執行到這行時就會跳到MathFunctions/CMakeLists.txt 繼續編譯 。

add_subdirectory(MathFunctions)

Day9 / MathFunctions / CMakeLists.txt

先將原始碼編譯成OBJECT檔,再將MathFunctions/include資料夾內的標頭檔使用PUBLIC的方式向上傳遞給main,否則main無法使用mysqrt的include目錄,造成編譯錯誤。

add_library(mysqrt OBJECT src/mysqrt.cpp)
# 將mysqrt.cpp編譯成名為mysqrt的object檔案
target_include_directories(mysqrt PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
# 將 ${CMAKE_CURRENT_SOURCE_DIR}/include 目錄加入 mysqrt 的 include 目錄,並且使用PUBLIC的方式向上傳遞給main,
# 否則main無法使用mysqrt的include目錄,造成編譯錯誤

接下來查看CMake_CURRENT_SOURCE_DIR和CMake_CURRENT_BINARY_DIR的值

message(STATUS "CMake_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
message(STATUS "CMake_CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}")
# 查看 CMake_CURRENT_SOURCE_DIR 和 CMake_CURRENT_BINARY_DIR 的值

因為沒有在add_subdirectory() 函式中指定二進制檔案輸出位置,
$ {CMAKE_CURRENT_BINARY_DIR} 的值預設會是 $ (PROJECT_BINARY_DIR)/filename 。

而我們在 build 資料夾中編譯,因此編譯過程中所產生的檔案路徑 $ (PROJECT_BINARY_DIR) 會等於build資料夾,因此 $ {CMAKE_CURRENT_BINARY_DIR} 值也就等於 ~/2023_iT_CMake/Day9/1/build/MathFunctions

kai@esoc:~/2023_iT_CMake/Day9/1/build$ cmake ..
-- The CXX compiler identification is GNU 11.4.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- MathFunctions CMake_CURRENT_SOURCE_DIR: /home/kai/2023_iT_CMake/Day9/1/MathFunctions
-- MathFunctions CMake_CURRENT_BINARY_DIR: /home/kai/2023_iT_CMake/Day9/1/build/MathFunctions
-- Configuring done
-- Generating done
-- Build files have been written to: /home/kai/2023_iT_CMake/Day9/1/build

Day9 / CMakeLists.txt

在將MathFunctions / src / mysqrt.cpp 編譯成二進制檔後,將執行檔與其鍊結。

target_link_libraries(main mysqrt)
# 將main與mysqrt鍊結

第二種情況

$ cd ~/2023_iT_CMake/Day9/2

目錄結構為

├── build
├── CMakeLists.txt
├── MathFunctions
│   └── MathFunctions
│       ├── CMakeLists.txt
│       ├── include
│       │   └── mysqrt.h
│       └── src
│           └── mysqrt.cpp
└── src
    └── main.cpp

頂層 CMakeLists.txt 需要將MathFunctions/MathFunctions加入下層目錄中

add_subdirectory(MathFunctions/MathFunctions)

$ cmake ..
$ make

kai@esoc:~/2023_iT_CMake/Day9/2/build$ cmake ..
-- The CXX compiler identification is GNU 11.4.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- MathFunctions CMake_CURRENT_SOURCE_DIR: /home/kai/2023_iT_CMake/Day9/2/MathFunctions/MathFunctions
-- MathFunctions CMake_CURRENT_BINARY_DIR: /home/kai/2023_iT_CMake/Day9/2/build/MathFunctions/MathFunctions
-- Configuring done
-- Generating done
-- Build files have been written to: /home/kai/2023_iT_CMake/Day9/2/build
kai@esoc:~/2023_iT_CMake/Day9/2/build$ make
[ 33%] Building CXX object MathFunctions/MathFunctions/CMakeFiles/mysqrt.dir/src/mysqrt.cpp.o
[ 33%] Built target mysqrt
[ 66%] Building CXX object CMakeFiles/main.dir/src/main.cpp.o
[100%] Linking CXX executable main
[100%] Built target main

第三種情況

$ cd ~/2023_iT_CMake/Day9/3

├── build
├── CMakeLists.txt <-- 這裡有一個
├── MathFunctions
│   ├── CMakeLists.txt <-- 這裡也有一個
│   └── MathFunctions
│       ├── CMakeLists.txt <-- 這裡還有一個
│       ├── include
│       │   └── mysqrt.h
│       └── src
│           └── mysqrt.cpp
└── src
    └── main.cpp

但是第二種情況比較少見,通常每一層目錄都會由CMakeLists.txt進行管理。
頂層 Day9 / CMakeLists.txt

add_subdirectory(MathFunctions)

下一層 Day9 / MathFunctions / CMakeLists.txt

add_subdirectory(MathFunctions)
kai@esoc:~/2023_iT_CMake/Day9/3/build$ cmake ..
-- The CXX compiler identification is GNU 11.4.0
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- MathFunctions CMake_CURRENT_SOURCE_DIR: /home/kai/2023_iT_CMake/Day9/3/MathFunctions/MathFunctions
-- MathFunctions CMake_CURRENT_BINARY_DIR: /home/kai/2023_iT_CMake/Day9/3/build/MathFunctions/MathFunctions
-- Configuring done
-- Generating done
-- Build files have been written to: /home/kai/2023_iT_CMake/Day9/3/build
kai@esoc:~/2023_iT_CMake/Day9/3/build$ make
[ 33%] Building CXX object MathFunctions/MathFunctions/CMakeFiles/mysqrt.dir/src/mysqrt.cpp.o
[ 33%] Built target mysqrt
[ 66%] Building CXX object CMakeFiles/main.dir/src/main.cpp.o
[100%] Linking CXX executable main
[100%] Built target main

還挺像套娃的


上一篇
[Day 8] Define Guard
下一篇
[Day 10] 靜態庫與動態庫
系列文
建構屬於自己的C/C++專案 : 我的30天CMake學習之旅29
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言